package com.lemurian.bankdata.action.base;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.struts2.ServletActionContext;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

import com.lemurian.bankdata.dto.LogHelper;
import com.lemurian.bankdata.lite.authentication.BankDataPrincipal;
import com.lemurian.bankdata.lite.enums.ApplicationCategory;
import com.lemurian.bankdata.lite.enums.UserActivityType;
import com.lemurian.bankdata.lite.logger.BankDataLogger;
import com.lemurian.bankdata.lite.struts.Pager;
import com.lemurian.bankdata.lite.struts.PartialList;
import com.lemurian.bankdata.lite.utils.GeneralConstant;
import com.lemurian.bankdata.lite.utils.GlobalFunction;
import com.lemurian.bankdata.services.ActivityLogService;
import com.lemurian.bankdata.services.CategoryService;
import com.lemurian.bankdata.services.GroupsService;
import com.lemurian.bankdata.services.MenuService;
import com.lemurian.bankdata.utils.BaseAction;
import com.lemurian.entity.Category;
import com.lemurian.entity.Groups;
import com.lemurian.entity.Menu;
import com.lemurian.entity.User;
import com.opensymphony.xwork2.Preparable;

public class GroupAction extends BaseAction implements Preparable {

	private static final long serialVersionUID = 1L;
	
	private BankDataLogger log = BankDataLogger.getLogger(GroupAction.class.getSimpleName());
	
	private Groups group = new Groups();
	private List<Groups> groups = new ArrayList<Groups>();
	
	private int userTypeId = 0;
	private List<Category> userTypes = new ArrayList<Category>();
	
	private Integer[] availableViewIds;
    private Integer[] choosenViewIds;
    private List<Menu> availableViewList;
    private List<Menu> choosenViewList;
	
    private int id = 0;
    
	private User user;
	private BankDataPrincipal principal;
	
	@Autowired private GroupsService groupsService;
	@Autowired private MenuService menuService;
	@Autowired private CategoryService categoryService;
	
	@Autowired 
	private ActivityLogService userActivityLogService;
	private LogHelper userActivityLog;
	
	@Override
	public void prepare() throws Exception {
		principal = (BankDataPrincipal) getSession().get(GeneralConstant.USER_PRINCIPAL);
		user = principal.getUser();
		
		if (id > 0) {
            try {
                group = groupsService.getGroup(id);
                
                if(group != null && group.getGroupType() != null) {
    				userTypeId = group.getGroupType().getId();
    			}

            	choosenViewList = group.getMenus();
                choosenViewIds = new Integer[choosenViewList.size()];

                int i = 0;
                Iterator<Menu> iterator = group.getMenus().iterator();
                while (iterator.hasNext()) {
                	
                	try {
                		Menu menu = (Menu) iterator.next();
                    	if(menu != null) {
                            choosenViewIds[i] = menu.getId();
                            i++;
                    	} else {
                    		choosenViewList.remove(menu);
                    		group.getMenus().remove(menu);
                    	}
                	} catch (Throwable t) {
						
					}
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            group = new Groups();
            choosenViewList = group.getMenus();
        }
	}
	
	@Override
	public String list() {
		log.info("list groups");

        setPreviousPage(GeneralConstant.LIST);
        try {
            PartialList<Groups> partialList = groupsService.findByCriteria(getStart(), getCount(),
                    getAscDesc().equalsIgnoreCase("asc") ? Order.asc(getOrderBy().length() > 0 ? getOrderBy() : "id") : Order.desc(getOrderBy().length() > 0 ? getOrderBy() : "id"),
                    group.getGroupName() != null && group.getGroupName().length() > 0 ? Restrictions.ilike("groupName", group.getGroupName(), MatchMode.ANYWHERE) : Restrictions.ne("id", new Integer(-1))
                    );
            
            groups = partialList.getList();

            setPager(Pager.generatePager(getStart(), getCount(), partialList.getTotal()));
            setPagerItem(Pager.generatePagerItem(getStart(), getCount(), partialList.getTotal()));
            
            partialList = null;
            
        } catch (Exception e) {
            return INPUT;
        }
        setMappedRequest(GeneralConstant.LIST);
        return SUCCESS;
	}
	
	@Override
	public String add() {
		setPreviousPage(GeneralConstant.ADD);
		setMappedRequest(GeneralConstant.SAVE);
		
		getSession().put(GeneralConstant.TIME_IN_SESSION, new Date());

        userTypes = categoryService.findByCriteria(Order.asc("id"),(Restrictions.eq("parent.id", ApplicationCategory.USER_TYPES.code())));
        
        try {
            if (availableViewList == null) {
                availableViewList = new LinkedList<Menu>();

                List<Menu> list = menuService.findAll();
                
                for (Menu menu : list) {
                    boolean same = false;
                    for (Menu menu2 : choosenViewList) {
                        if (menu != null && menu.getId() == menu2.getId()) {
                            same = true;
                            break;
                        }
                    }
                    if (!same) {
                        availableViewList.add(menu);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("avalaible list " + availableViewList.size());
        
        return SUCCESS;
	}
	
	@Override
	public String save() {
		
		group.setMenus(new ArrayList<Menu>());
		groupsService.save(group);
		try {
			if (choosenViewIds != null) {
				
				System.out.println(": : : : : CHOOSEN SIZE   : "+choosenViewIds.length);
				
				group.getMenus().clear();
				List<Menu> menuList =  menuService.findAll(Order.asc("id"));
				for (int i = 0; i < choosenViewIds.length; i++) {
                    for (Menu link : menuList) {
                        if (choosenViewIds[i] == link.getId()) {
                            group.getMenus().add(link);
                            break;
                        }
                    }
                }
				menuList = null;
			}
			
			String message = "";	
			if(id > 0) {
				group.setUpdateBy(user.getName());
				group.setUpdateDate(new Timestamp(System.currentTimeMillis()));

				message = "Update";
				userActivityLog = new LogHelper(user, UserActivityType.UPDATE_GROUP);
			} else {
				group.setCreateBy(user.getName());
				group.setCreateDate(new Timestamp(System.currentTimeMillis()));
				
				message = "Add";
				userActivityLog = new LogHelper(user, UserActivityType.ADD_GROUP);
			}
			
			group.setGroupType(null);
			
			Category groupType = null;
			if(userTypeId>0) {
				groupType = (Category) categoryService.findById(userTypeId);
			}
			
			if(groupType != null) {
				group.setGroupType(groupType);
			}
			
			group.setStatus(Boolean.TRUE);
			groupsService.save(group);
			
			try {
                message += " " + group.getGroupName() + " is success";
                addCustomActionMessage(message);
                
                log.sInfo(" :: User [%s:%s] is successfully save Group [%s:%s]", user.getId(), user.getName(), group.getId(), group.getGroupName());
                userActivityLog.setStatus(LogHelper.SUCCESS_ACTIVITY);
            } catch (Exception e) {
                message += " " + group.getGroupName() + " is failed, message : "+e.getMessage();
                addCustomActionError(message);
                log.sInfo(" :: Error was raised when User [%s:%s] save Group [%s:%s]", user.getId(), user.getName(), group.getId(), group.getGroupName());
                
                //set activity log status into failed
                userActivityLog.setStatus(LogHelper.FAILED_ACTIVITY);
                userActivityLog.setErrorMsg(e.getMessage());
            }
            
            userActivityLog.setSessionId(ServletActionContext.getRequest().getSession().getId());
            userActivityLog.setStartDate((Date) getSession().get(GeneralConstant.TIME_IN_SESSION));
            userActivityLog.getAdditionalParams().add(group.getGroupName());
            userActivityLogService.saveUserActivity(userActivityLog);
            getSession().remove(GeneralConstant.TIME_IN_SESSION);
		} catch (Throwable t) {
			addCustomActionError(t.getMessage());
			t.printStackTrace();
		}
		
		setMappedRequestFullPath("/GroupAction_list.do");
		return GeneralConstant.REDIRECT;
	}

	@Override
	public String delete() {
		try {
			groupsService.delete(group);
			
			userActivityLog = new LogHelper(user, UserActivityType.DELETE_GROUP);
			
			String message = "";
            try {
                message = "Delete " + group.getGroupName() + " is success";
                addCustomActionMessage(message);
                log.sInfo(" :: User [%s:%s] is successfully delete Group [%s:%s]", user.getId(), user.getName(), group.getId(), group.getGroupName());

                //check if activity is success
                userActivityLog.setStatus(LogHelper.SUCCESS_ACTIVITY);
            } catch (Exception e) {
                message = "Delete " + group.getGroupName() + " is failed, message : "+e.getMessage();
                addCustomActionError(message);
                log.sInfo(" :: Error was raised when User [%s:%s] delete Group [%s:%s]", user.getId(), user.getName(), group.getId(), group.getGroupName());
                
                //set activity log status into failed
                userActivityLog.setStatus(LogHelper.FAILED_ACTIVITY);
                userActivityLog.setErrorMsg(e.getMessage());
            }
            //save activity log
            userActivityLog.getAdditionalParams().add(group.getGroupName());
            userActivityLogService.saveUserActivity(userActivityLog);
			
		} catch (Throwable t) {
			addCustomActionError(t.getMessage());
		}
		
		setMappedRequestFullPath("/GroupAction_list.do");
		return GeneralConstant.REDIRECT;
	}

	@Override
	public String detail() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String edit() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String update() {
		// TODO Auto-generated method stub
		return null;
	}

	public Groups getGroup() {
		return group;
	}

	public void setGroup(Groups group) {
		this.group = group;
	}

	public List<Groups> getGroups() {
		return groups;
	}

	public void setGroups(List<Groups> groups) {
		this.groups = groups;
	}
	
	public int getId() {
		return id;
	}

	public void setId(String id) {
		int id_ = 0;
		if(id != null && !id.equalsIgnoreCase("0")) {
			id = GlobalFunction.decodeParameter(id);
	        id_ = Integer.parseInt(id);
		}
        this.id = id_;
	}

	public Integer[] getAvailableViewIds() {
		return availableViewIds;
	}

	public void setAvailableViewIds(Integer[] availableViewIds) {
		this.availableViewIds = availableViewIds;
	}

	public Integer[] getChoosenViewIds() {
		return choosenViewIds;
	}

	public void setChoosenViewIds(Integer[] choosenViewIds) {
		this.choosenViewIds = choosenViewIds;
	}

	public List<Menu> getAvailableViewList() {
		return availableViewList;
	}

	public void setAvailableViewList(List<Menu> availableViewList) {
		this.availableViewList = availableViewList;
	}

	public List<Menu> getChoosenViewList() {
		return choosenViewList;
	}

	public void setChoosenViewList(List<Menu> choosenViewList) {
		this.choosenViewList = choosenViewList;
	}

	public int getUserTypeId() {
		return userTypeId;
	}

	public void setUserTypeId(String userTypeId) {
		int id_ = 0;
		if(userTypeId != null && !userTypeId.equalsIgnoreCase("0")) {
			userTypeId = GlobalFunction.decodeParameter(userTypeId);
	        id_ = Integer.parseInt(userTypeId);
		}
        this.userTypeId = id_;
	}

	public List<Category> getUserTypes() {
		return userTypes;
	}

	public void setUserTypes(List<Category> userTypes) {
		this.userTypes = userTypes;
	}
	
}